package server;
import java.io.*;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.Hashtable;

/**
 * <p>Title: Request.java</p>
 *
 * <p>Description: Used to store and process requests that come from the client
 * to the server. </p>
 *
 * <p>Copyright: Copyright (c) 2005</p>
 *
 * <p>Company: </p>
 * @author Tracie Hong and Luping May
 * @version 1.0
 */
public class Request {
    //private boolean aliasesUsed;
    //private String body;

    private Hashtable <String, String> header;


    private String method;
    private String query;
    //private String requestLine;
    BufferedReader startOfBody;
    int statusCode;
    private String URI;
    private String version;
    private Vector <String> tags;
    private String FirstLine;
    private String fristRequestLine;
    private String User_Agent;
    private String Accept;
    private String Accept_Language;
    private String Accept_Encoding;
    private String Accept_Charset;
    private String Keep_Alive;
    private String Connection;
    private boolean isScript;
    private String PATH_INFO;
    private String PATH_TRANSLATED;
    private String OriURI;
    private String SCRIPT_NAME;
    private HttpdConf confFile;
    private boolean validMethod = true;
    private String[] queryString;
    private String Content_Type;
    private String Content_Length;
    private String Body;
  /**
   * Default constructor used to reset your variables and data structures for
   * each new incoming request.
   */
  public Request() {
    method = "";
    URI = "";
    version = "";
    fristRequestLine = "";
    query = "";
    header = new Hashtable <String, String> ();
    tags = new Vector <String> ();
    User_Agent = "";
    Accept = "";
    Accept_Language = "";
    Accept_Encoding = "";
    Accept_Charset = "";
    Keep_Alive = "";
    Connection = "";
    isScript = false;
    PATH_INFO = "";
    PATH_TRANSLATED = "";
    OriURI = "";
    SCRIPT_NAME = "";
    Content_Type = "";
    Body = "";
  }


  /**
   * Parse the incoming request depending on the type of request you are
   * receiving. This information is found from the first line of the incoming
   * request. You will also want to check and make sure the request you are
   * receiving is a valid request. If the request is not valid, throw an error
   * using the http error codes.
   *
   * @param inMsg BufferedReader which grabs the incoming message from the
   *   client socket
   */
  public void parse(BufferedReader inMsg) {
    try{
        FirstLine = inMsg.readLine();
        parseFirstLine(FirstLine);
        createRequest(inMsg);
    }catch(IOException e){
        System.err.println("Error: " + e.getMessage());
    }
  }

  /**
   * Used to first check whether a requested file path has an alias set within
   * the configuration file and if so, replaces the alias of the file or
   * directory with the real path. This way, the server can find the right file
   * in the tree.
   *
   * HINT: Remember that any one path can have multiple aliases found within the
   * httpd.conf file. For example, the URI
   * http://www.blah.net/blah/help/hello.html could have an alias where blah is
   * equivalent to http://www.blah.net/blah_blah_blah and help could be an alias
   * for http://www.blah.net/blah_blah_blah/bleh/help. Another thing to note is
   * that your URI could also include script aliases which means you may be
   * required to run a cgi script.
   *
   * @param config HttpdConf Object which contains all the information on how
   *   the server is configured.
   */
  public void setHttpdConf(HttpdConf config) {
      /*
      confFile = config;
     StringTokenizer URIAnalysis = new StringTokenizer(URI,"/");
      String alias = "/", link;
      Boolean flag = false;
      if (!URIAnalysis.hasMoreTokens()){
              URI = config.getDocumentRoot() + "\\index.html";
              flag = true;
      }

      while(URIAnalysis.hasMoreTokens()){
         // System.out.println(URI);
          alias = URIAnalysis.nextToken();
          //alias = alias.concat(URIAnalysis.nextToken());
          //System.out.println(alias);
          link = config.solveAlias(alias);
          //System.out.println(link);
          if(link != null){
              URI = URI.replace(alias, link);
              flag = true;
          }
      }
       if (URI.contains("?")){
        int index= URI.indexOf("?");
        //System.out.println(URI);
        query = URI.substring(index+1, URI.length());
        URI = URI.substring(0, index);
        //System.out.println(URI);
      }
      if (!flag)
          URI = config.getDocumentRoot() + URI;
      */
       confFile = config;
      StringTokenizer URIAnalysis = new StringTokenizer(URI,"/");
      String alias = "/", link;
      Boolean flag = false;
      if (!URIAnalysis.hasMoreTokens()){
              URI = config.getDocumentRoot() + "\\index.html";
              flag = true;
      }

      while(URIAnalysis.hasMoreTokens()){
          alias = alias.concat(URIAnalysis.nextToken());
          //alias = URIAnalysis.nextToken();
          if(config.isScript(alias)){
            isScript = true;
          }
          link = config.solveAlias(alias);

          if(link != null){
              URI = URI.replace(alias, link);
              flag = true;
          }
      }

      if (!flag)
          URI = config.getDocumentRoot() + URI;

      System.out.println(URI);
      setVarFirstLine();
      setVarNotFirstLine();
      
  }
  
	//function to print out all the information from the request. Used for debugging
  /**
   * Print function used for debugging purposes. Helpful to make sure you are
   * parsing the incoming request properly.
   */
  public void print() {
    System.out.println("The method was " + method);
    System.out.println("The Request URL was " + URI);
    System.out.println("The query string was " + query);
    System.out.println("The HTTP version is " + version);
    System.out.println("The following headers were included:");
    for (int i = 0; i < tags.size(); i++) {
      System.out.println(tags.get(i) + ": " + header.get(tags.get(i)));
    }
    //System.out.println("The message body was: \n" + body);
  }

  /**
   * private function used by request object to parse the information passed
   * through from the client to the server and save it for future use. The type
   * of request can be found on this first line of the request.
   *
   * @param first String representation of the first line of the request from
   *   the client. Passed in as one long string which can easily be parsed.
   */
  private void parseFirstLine(String first) {
    fristRequestLine = first;
    StringTokenizer sTokenizer;
    sTokenizer = new StringTokenizer(fristRequestLine);
    method = sTokenizer.nextToken();
    URI = sTokenizer.nextToken();
    OriURI = URI;
    version = sTokenizer.nextToken();
    validMethod  = checkRequest();
  }

  /**
   * private function used by the request object to determine whether an incoming
   * request is a valid request or not. Useful when throwing error messages.
   *
   * @return true if request is valid, false otherwise
   */
  private boolean checkRequest() {
    if((method.equals("GET")) || (method.equals("HEAD")) ||
       (method.equals("POST")) || (method.equals("PUT"))){
        return true;
    }
    return false;
  }

  /**
   * private function used by the request object to grab variables that may have
   * been passed to the server when the request was made. Remember that GET and
   * HEAD requests include their variables on the first line of the request while
   * POST and PUT requests include their variables within the body of the
   * message.
   */
  private void setVarFirstLine() {
    if(isScript){
        StringTokenizer st1 = new StringTokenizer(URI,"/");
        String tempURI="";
        String test="";
        while(st1.hasMoreTokens()){
            test = st1.nextToken();
            if(test.contains(".")){
                if(test.contains("?")){
                    if(test.contains(test.substring(test.indexOf("."), test.indexOf("?")))){

                        SCRIPT_NAME = test.substring(0,test.indexOf("?"));
                        query = test.substring(test.indexOf("?")+1, test.length());
                        StringTokenizer st = new StringTokenizer(query,"&");
                        queryString = new String[st.countTokens()];
                        int i = 0;
                        while(st.hasMoreTokens()){
                          queryString[i++] = st.nextToken();
                        }
                        URI = URI.substring(0,URI.indexOf(SCRIPT_NAME)+SCRIPT_NAME.length());
                        break;
                    }
                }

                else if(test.contains(test.substring(test.indexOf("."), test.length()))){
                    SCRIPT_NAME = test;
                    
                    while(st1.hasMoreTokens()){
                        PATH_INFO = PATH_INFO.concat("/" + st1.nextToken());
                    }

                    System.out.print("PATH_INFO:" + PATH_INFO);
                    if(PATH_INFO.contains("?")){
                        query = PATH_INFO.substring(PATH_INFO.indexOf("?")+1, PATH_INFO.length());
                        PATH_INFO = PATH_INFO.substring(0,PATH_INFO.indexOf("?"));
                        StringTokenizer st = new StringTokenizer(query,"&");
                        queryString = new String[st.countTokens()];
                        int i = 0;
                        while(st.hasMoreTokens()){
                                queryString[i++] = st.nextToken();
                        }
                    }

                    else
                        queryString = new String[0];
                    URI = URI.substring(0,URI.indexOf(SCRIPT_NAME)+SCRIPT_NAME.length());
                    break;
                }
            }
        }
      }
  }

  /**
   * private function used by the request object to grab variables that may have
   * been passed to the server when the request was made. Remember that POST and
   * PUT requests include their variables within the body of the message and not
   * in the first line, so another method is needed to retrieve these variables.
   */
  private void setVarNotFirstLine() {
    User_Agent = header.get("User-Agent");
    Accept = header.get("Accept");
    Accept_Language = header.get("Accept-Language");
    Accept_Encoding = header.get("Accept-Encoding");
    Accept_Charset = header.get("Accept-Charset");
    Keep_Alive = header.get("Keep-Alive");
    Connection = header.get("Connection");
    if(method.equals("PUT") || method.equals("POST")){
        Content_Type = header.get("Content-Type");
        Content_Length = header.get("Content-Length");
    }
  }

  /**
   * private function used by the request object to parse the rest of the request
   * message (e.g. other headers and the body of the message) from the client so
   * it can be used later when actual processing of the request happens.
   *
   * @param inFile BufferedReader object that comes through the socket. Needs to
   *   be processed properly before the data stored within it can be used.
   */
  private void createRequest(BufferedReader inFile) {
        String inMsgAnalysis;
        StringTokenizer sTokenizer;
        String tempString;
        String s;
        int i = 0;
        try{
            if(checkRequest()){
                //while ((inMsgAnalysis = inFile.readLine()) != null)  {
                while((inFile.ready())){
                    inMsgAnalysis = inFile.readLine();
                    sTokenizer = new StringTokenizer(inMsgAnalysis);
                    System.out.println(inMsgAnalysis);
                    if(sTokenizer.hasMoreTokens()){
                        tempString = sTokenizer.nextToken();
                        //System.out.println(tempString);
                        System.out.println(tempString);
                        tags.add(tempString);
                        header.put(tags.get(i), inMsgAnalysis.substring(tempString.length()));
                        i++;

//                        System.out.println("Method: " + method);
//                        if(tempString.contains("Content-Length:"))
//                            if(method.equals("POST")){
//                                System.out.println("Ture");
//                                break;
////                                while(inFile.ready()){
////
////                                }
//                            }
                    }
                }
            }
            
        }catch(IOException e){
            System.err.println("Error: " + e.getMessage() );
        }
      /*
      String inMsgAnalysis = null;
        StringTokenizer sTokenizer;
        int i = 0;
        try{
            if(checkRequest()){
                while (inFile.ready()) {
                    inMsgAnalysis = inFile.readLine();
                    sTokenizer = new StringTokenizer(inMsgAnalysis);

                    if(sTokenizer.hasMoreTokens()){
                        tags.add(sTokenizer.nextToken());
                        header.put(tags.get(i), sTokenizer.nextToken());
                        i++;
                    }
                }
            }
        }catch(IOException e){
            System.err.println("Error: " + e.getMessage() );
        }
       */
  }

  public String getQuery(){return query;}
  public String getURI(){return URI;}
  public String getMethod(){return method;}
  public String getVersion(){return version;}
  public String getFirstLine(){return fristRequestLine;}
  public Vector getTags(){return tags;}

  public Hashtable getHeaders(){return header;}

 // public static Hashtable getHeaders(){return header;}

  public String getUserAgent(){return User_Agent;}
  public String getAccept(){return Accept;}
  public String getAcceptLanguage(){return Accept_Language;}
  public String getAcceptEncoding(){return Accept_Encoding;}
  public String getAcceptCharset(){return Accept_Charset;}
  public String getKeepAlive(){return Keep_Alive;}
  public String getConnection(){return Connection;}
  public boolean isURIScript(){return isScript;}
  public String getSCRIPTNAME(){return SCRIPT_NAME;}
  public Hashtable getHeader(){return header;}
  public Vector getAuth(){return confFile.getAuthentication();}
  public boolean getValidMethod(){return validMethod;}
  public String getCGIHandler() {return confFile.getCGIHandler(SCRIPT_NAME);}
  public String[] getQueryString(){return queryString;}
  public String getENV(String string){
      String temp = header.get(string);
      System.out.println(temp);
      String empty = "";
      if(temp == null)
        return empty;
      else
        return temp;
  }
  public String getPathInfo(){return PATH_INFO;}
  public String getPathTranslated(){return PATH_TRANSLATED;}
}
